package nl.tudelft.jpacman.lenve2;

import nl.tudelft.jpacman.board.Square;
import nl.tudelft.jpacman.level.Pellet;
import nl.tudelft.jpacman.level.Player;
import nl.tudelft.jpacman.level.PlayerCollisions;
import nl.tudelft.jpacman.npc.Ghost;
import nl.tudelft.jpacman.points.PointCalculator;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

import static org.mockito.Mockito.*;

/**
 * A test class for {@link PlayerCollisions}.
 */
public class PlayerCollisionTest {

    // Fields
    private PlayerCollisions playerCollisions;
    private PointCalculator pointCalculator;
    private Player playerMock;
    private Ghost ghostMock;
    private Pellet pelletMock;

    /**
     * Sets up the test environment before each test.
     */
    @BeforeEach
    public void setUp() {
        pointCalculator = mock(PointCalculator.class);
        playerCollisions = new PlayerCollisions(pointCalculator);
        playerMock = mock(Player.class);
        ghostMock = mock(Ghost.class);
        pelletMock = mock(Pellet.class);
    }

    /**
     * Tests the collision between a player and a pellet.
     * Verifies that the point calculator increases the player's score
     * and the pellet leaves the square where it was located.
     */
    @Test
    @DisplayName("Player与Pellet发生碰撞")
    public void testPlayerVsPellet_collision() {
        playerCollisions.collide(playerMock,pelletMock);
        verify(pointCalculator).consumedAPellet(playerMock,pelletMock);
        verify(pelletMock).leaveSquare();
    }

    /**
     * Tests the collision between a ghost and a player.
     * Verifies that the player dies and sets the killer to be the ghost.
     */
    @Test
    @DisplayName("Player与Ghost发生碰撞(Ghost为碰撞体)")
    void testGhostCollidesWithPlayer() {
        playerCollisions.collide(ghostMock, playerMock);
        verify(playerMock).setAlive(false);
        verify(playerMock).setKiller(ghostMock);
    }

    /**
     * Tests the collision between two ghosts.
     * Verifies that nothing happens.
     */
    @Test
    @DisplayName("Ghost与Ghost发生碰撞")
    void testGhostCollidesWithGhost() {
        playerCollisions.collide(ghostMock, ghostMock);
        verifyNoMoreInteractions(ghostMock, ghostMock);
    }

    /**
     * Tests the collision between a player and a ghost.
     * Verifies that the player dies and sets the killer to be the ghost.
     */
    @Test
    @DisplayName("Player与Ghost发生碰撞(Player为碰撞体)")
    void testPlayerCollidesWithGhost() {
        playerCollisions.collide(playerMock, ghostMock);
        verify(playerMock).setAlive(false);
        verify(playerMock).setKiller(ghostMock);
    }

    /**
     * Tests the collision between a ghost and a pellet.
     * Verifies that nothing happens.
     */
    @Test
    @DisplayName("Ghost与Pellet发生碰撞")
    void testGhostCollidesWithPellet() {
        playerCollisions.collide(ghostMock, pelletMock);
        verifyNoMoreInteractions(ghostMock, pelletMock);
    }

    /**
     * Tests when there is no collision.
     * Verifies that nothing happens.
     */
    @Test
    @DisplayName("什么都没有发生")
    void testNothingHappens() {
        playerCollisions.collide(pelletMock, pelletMock);
        verifyNoMoreInteractions(pelletMock, pelletMock);
    }
}
